<?

abstract class bf_auth {

	abstract protected function get_password($username, $realm);

	protected $opts;
	protected $log;
	private $username = false;

	public function __construct($options = array()) {
		$this->opts = array_merge(array(
			'realm' => 'realm',
			'content' => 'Unauthorized',
			'log' => dirname(__FILE__) . '/../../logs/auth.log',
		), $options);
		$this->log = new bf_log($this->opts['log']);
	}

	private function http_digest_parse($txt) {
		$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
		$data = array();
		$keys = implode('|', array_keys($needed_parts));
		preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
		foreach ($matches as $m) {
			$data[$m[1]] = $m[3] ? $m[3] : $m[4];
			unset($needed_parts[$m[1]]);
		}
		return $needed_parts ? false : $data;
	}

	protected function get_a1($username, $realm) {
		if (!($passwd = $this->get_password($username, $realm)))
			return false;
		return md5($username . ':' . $realm . ':' . $passwd);
	}

	private function http_check_user($response_to_check, $name, $uri, $nonce, $nc, $cnonce, $qop) {

		$ts = date('Y-m-d H:i:s');
		$hn = @$_SERVER['SERVER_NAME'];

		if (!($A1 = $this->get_a1($name, $this->opts['realm']))) {
			$this->log->append("$ts $hn [$name] login failed\n");
			return false;
		}

		$A2 = md5($_SERVER['REQUEST_METHOD'].':' . $uri);
		$valid_response = md5($A1.':'.$nonce.':'.$nc.':'.$cnonce.':'.$qop.':'.$A2);
		if ($response_to_check != $valid_response) {
			$this->log->append("$ts $hn [$name] user not found\n");
			return false;
		}

		$this->username = $name;
		$this->log->append("$ts $hn [$name] authorized\n");
		return true;
	}

	private function send_headers() {
		@header('HTTP/1.1 401 Unauthorized');
		@header('WWW-Authenticate: Digest realm="' . $this->opts['realm'] . '",qop="auth",nonce="' . uniqid() . '",opaque="' . md5($this->opts['realm']) . '"');
	}

	public function trap() {

		if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
			$this->send_headers();
			echo($this->opts['content']);
			exit(0);
		}

		if (false
			|| !($data = $this->http_digest_parse($_SERVER['PHP_AUTH_DIGEST']))
			|| !$this->http_check_user($data['response'], $data['username'], $data['uri'], $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'])
		) {
			$this->send_headers();
			echo($this->opts['content']);
			exit(0);
		}
	}

	public function get_username() {
		return $this->username;
	}

	public function get_value($name) {
		if ($name == 'username')
			return $this->get_username();
		return null;
	}
}

?>